3.7.ACL权限管理(zero-rbac)
白皮书中的权限管理主要包括两部分:管理端和消费端:
-
管理端:可扩展面板式架构,现阶段版本支持 菜单管理、流程定制 两类,您可以扩展自己所需的不同权限管理的结构。
-
消费端:XBAC模型:基于角色的RBAC(Role)、基于属性的ABAC(Attribute)、基于策略的PBAC(Policy)。
|
Zero在线教程中讲解过可插拔模式的认证组件,此处略过认证部分( |
3.7.1.核心概念
3.7.1.1.XBAC模型
Zero中的基本权限主体模型如下:
上图中的核心概念如下:
| 实体表 | 概念 | 含义 |
|---|---|---|
S_USER |
用户 |
登录系统专用账号信息表。 |
S_ROLE |
角色 |
和账号关联的角色信息表。 |
S_GROUP |
用户组 |
和账号关联的用户组信息表。 |
S_PERMISSION |
权限 |
和角色相关联的权限记录表。 |
S_PERM_SET |
权限集 |
服务于权限定义的权限集合表,主要用于管理段构造权限集合实现批量授权。 |
S_ACTION |
操作 |
隶属于权限记录的操作集合,操作最终会绑定到对应的操作主体上。 |
常用的基本配置中,只要资源所需操作级别和基础算法模型计算的最终权限路径和用户所拥有的权限路径是通的,那么就可以实现基础权限的认证,这部分内容在完成本章节所有讲解之后会有更深入的说明。 |
安全操作 S_ACTION 对端关联到资源表 S_RESOURCE 和资源形成1对1的绑定,资源中定义的就是访问资源的基本要求,而S_ACTION中计算出来的结果就是登录账号所拥有的资源访问资格,当资源访问资格满足了资源基本要求时就认证通过,证明当前账号有权限访问该资源。但是、但是、但是——此处只是解决了账号:能不能 的问题,在资源访问之后还会有两张专用的数据表来执行 访问多少 的问题,这是Zero中数据域的实现原理,在后续的 N维安全视图 中加以说明。
3.7.1.2.多态身份(Profile)
Zero中由于复杂的多对多结构,最终会形成不同的多态身份(Profile),S_RESOURCE 表中有如下字段对资源访问资格执行定义:
| 字段名 | 含义 | 取值 |
|---|---|---|
MODE_ROLE |
按角色查找资源的模式 |
UNION、EAGER、LAZY、INTERSECT |
MODE_GROUP |
按用户组查找资源的模式 |
HORIZON、CRITICAL、OVERLOOK |
MODE_TREE |
用户组继承和非继承树模式查找 |
EXTEND、PARENT、CHILD、INHERIT |
上述取值是资源对多态身份的定义,最终形成的多态身份 Profile 的值列表如下(举例定义角色和组的优先级):
|
不含组模式
假设用户包含如下信息,这种模式(高频使用模式)下 MODE_GROUP / MODE_TREE 都设置成 NULL:
R1(H):P1、P2、P3,高优先级角色,包含三条权限记录。
R2(L):P2、P4,低优先级角色,包含两条权限记录。
| 值 | 含义 |
|---|---|
USER_UNION |
|
USER_EAGER |
|
USER_LAZY |
|
USER_INTERSECT |
|
用户组模式
假设用户包含如下信息:
用户组结构如下(此处不列举组所对应的权限集):
G10
/ \
G20 G21
/ \ \
G30 G31 G32
而登录用户只包含如下三个用户组:
G20(H):高优先级用户组
G31(M):中优先级用户组
G32(L):低优先级用户组
全量优先级:
G10 > G20 > G21 > G30 > G31 > G32
| 值 | 组计算 | 角色计算 | 计算流程 |
|---|---|---|---|
HORIZON_UNION |
UNION模式计算单个用户组关联角色权限集,再将三个组的权限集合并。 |
||
HORIZON_EAGER |
EAGER模式计算单个用户组关联角色权限集,再将三个组的权限集合并。 |
||
HORIZON_LAZY |
LAZY模式计算单个用户组关联角色权限集,再将三个组的权限集合并。 |
||
HORIZON_INTERSECT |
INTERSECT模式计算单个用户组关联角色权限集,再将三个组的权限集合并。 |
||
CRITICAL_UNION |
UNION模式计算高优先级组的权限集。 |
||
CRITICAL_EAGER |
EAGER模式计算高优先级组的权限集。 |
||
CRITICAL_LAZY |
LAZY模式计算高优先级组的权限集。 |
||
CRITICAL_INTERSECT |
INTERSECT模式计算高优先级的权限集。 |
||
OVERLOOK_UNION |
UNION模式计算低优先级组的权限集。 |
||
OVERLOOK_EAGER |
EAGER模式计算低优先级组的权限集。 |
||
OVERLOOK_LAZY |
LAZY模式计算低优先级组的权限集。 |
||
OVERLOOK_INTERSECT |
INTERSECT模式计算低优先级组的权限集。 |
||
PARENT_HORIZON_UNION |
先查找三个组的父组,再按UNION模式计算权限集。 |
||
PARENT_HORIZON_EAGER |
先查找三个组的父组,再按EAGER模式计算权限集。 |
||
PARENT_HORIZON_LAZY |
先查找三个组的父组,再按LAZY模式计算权限集。 |
||
PARENT_HORIZON_INTERSECT |
先查找三个组的父组,再按INTERSECT模式计算权限集。 |
||
PARENT_CRITICAL_UNION |
查找优先级最高组的父组,再按UNION模式计算权限集。 |
||
PARENT_CRITICAL_EAGER |
查找优先级最高组的父组,再按EAGER模式计算权限集。 |
||
PARENT_CRITICAL_LAZY |
查找优先级最高组的父组,再按LAZY模式计算权限集。 |
||
PARENT_CRITICAL_INTERSECT |
查找优先级最高组的父组,再按INTERSECT模式计算权限集。 |
||
PARENT_OVERLOOK_UNION |
查找优先级最低组的父组,再按UNION模式计算权限集。 |
||
PARENT_OVERLOOK_EAGER |
查找优先级最低组的父组,再按EAGER模式计算权限集。 |
||
PARENT_OVERLOOK_LAZY |
查找优先级最低组的父组,再按LAZY模式计算权限集。 |
||
PARENT_OVERLOOK_INTERSECT |
查找优先级最低组的父组,再按INTERSECT模式计算权限集。 |
||
CHILD_HORIZON_UNION |
查找所有组的子组,再按UNION模式计算权限集。 |
||
CHILD_HORIZON_EAGER |
查找所有组的子组,再按EAGER模式计算权限集。 |
||
CHILD_HORIZON_LAZY |
查找所有组的子组,再按LAZY模式计算权限集。 |
||
CHILD_HORIZON_INTERSECT |
查找所有组的子组,再按INTERSECT模式计算权限集。 |
||
CHILD_CRITICAL_UNION |
查找优先级最高组的子组,再按UNION模式计算权限集。 |
||
CHILD_CRITICAL_EAGER |
查找优先级最高组的子组,再按EAGER模式计算权限集。 |
||
CHILD_CRITICAL_LAZY |
查找优先级最高组的子组,再按LAZY模式计算权限集。 |
||
CHILD_CRITICAL_INTERSECT |
查找优先级最高组的子组,再按INTERSECT模式计算权限集。 |
||
CHILD_OVERLOOK_UNION |
(无权限)查找优先级最低组的子组,再按UNION模式计算权限集。 |
||
CHILD_OVERLOOK_EAGER |
(无权限)查找优先级最低组的子组,再按EAGER模式计算权限集。 |
||
CHILD_OVERLOOK_LAZY |
(无权限)查找优先级最低组的子组,再按LAZY模式计算权限集。 |
||
CHILD_OVERLOOK_INTERSECT |
(无权限)查找优先级最低组的子组,再按INTERSECT模式计算权限集。 |
||
INHERIT_HORIZON_UNION |
查找所有组父组包含本组,再按UNION模式计算权限集。 |
||
INHERIT_HORIZON_EAGER |
查找所有组父组包含本组,再按EAGER模式计算权限集。 |
||
INHERIT_HORIZON_LAZY |
查找所有组父组包含本组,再按LAZY模式计算权限集。 |
||
INHERIT_HORIZON_INTERSECT |
查找所有组父组包含本组,再按INTERSECT模式计算权限集。 |
||
INHERIT_CRITICAL_UNION |
查找优先级高组的父组包含本组,再按UNION模式计算权限集。 |
||
INHERIT_CRITICAL_EAGER |
查找优先级高组的父组包含本组,再按EAGER模式计算权限集。 |
||
INHERIT_CRITICAL_LAZY |
查找优先级高组的父组包含本组,再按LAZY模式计算权限集。 |
||
INHERIT_CRITICAL_INTERSECT |
查找优先级高组的父组包含本组,再按INTERSECT模式计算权限集。 |
||
INHERIT_OVERLOOK_UNION |
查找优先级低组的父组包含本组,再按UNION模式计算权限集。 |
||
INHERIT_OVERLOOK_EAGER |
查找优先级低组的父组包含本组,再按EAGER模式计算权限集。 |
||
INHERIT_OVERLOOK_LAZY |
查找优先级低组的父组包含本组,再按LAZY模式计算权限集。 |
||
INHERIT_OVERLOOK_INTERSECT |
查找优先级低组的父组包含本组,再按INTERSECT模式计算权限集。 |
||
EXTEND_HORIZON_UNION |
查找所有组子组包含本组,再按UNION模式计算权限集。 |
||
EXTEND_HORIZON_EAGER |
查找所有组子组包含本组,再按EAGER模式计算权限集。 |
||
EXTEND_HORIZON_LAZY |
查找所有组子组包含本组,再按LAZY模式计算权限集。 |
||
EXTEND_HORIZON_INTERSECT |
查找所有组子组包含本组,再按INTERSECT模式计算权限集。 |
||
EXTEND_CRITICAL_UNION |
查找优先级高组的子组包含本组,再按UNION模式计算权限集。 |
||
EXTEND_CRITICAL_EAGER |
查找优先级高组的子组包含本组,再按EAGER模式计算权限集。 |
||
EXTEND_CRITICAL_LAZY |
查找优先级高组的子组包含本组,再按LAZY模式计算权限集。 |
||
EXTEND_CRITICAL_INTERSECT |
查找优先级高组的子组包含本组,再按INTERSECT模式计算权限集。 |
||
EXTEND_OVERLOOK_UNION |
查找优先级低组的子组包含本组,再按UNION模式计算权限集。 |
||
EXTEND_OVERLOOK_EAGER |
查找优先级低组的子组包含本组,再按EAGER模式计算权限集。 |
||
EXTEND_OVERLOOK_LAZY |
查找优先级低组的子组包含本组,再按LAZY模式计算权限集。 |
||
EXTEND_OVERLOOK_INTERSECT |
查找优先级低组的子组包含本组,再按INTERSECT模式计算权限集。 |
|
多态身份Profile是整个 Zero权限框架中的一个 过度设计 的典范,从实际场景看起来真正使用到这部分的内容仅局限于 对用户而言,一旦登录之后,自己的 Profile 就已经固定,而资源需求要求的Profile则不一定固定,属于变量,最终计算结果近似于查找最短路径,达到用户组这个级别的额外的变化模式(包括继承、包括派生、包括限制、包括组合等),最终 Zero权限框架中合计支持64种Profile配置,如此就解决了资源 能不能 访问的问题。 |
3.7.1.3.N维安全视图(View)
前文解决了资源 能不能 访问的问题,本章就在可访问的基础上解决 访问多少 的问题,Zero权限框架中的 S_RESOURCE 和 S_ACTION 是强绑定关系,它们之间只会单纯对比操作级别和资源需求级别是否可访问,一旦访问成功,就会延生读写操作的边界,在Zero权限框架中读写边界的划定取决于安全视图 S_VIEW 中的定义。
安全视图基础
安全视图的基础维度如下:
| 字段名 | 含义 | 取值 |
|---|---|---|
NAME |
视图名称 |
默认取值 DEFAULT。 |
POSITION |
视图位置 |
默认取值 DEFAULT。 |
OWNER_TYPE |
视图所属 |
只包含两种:ROLE-角色视图,USER-用户视图。 |
OWNER |
视图所属者ID |
如果是角色视图则是角色ID,如果是用户视图则是用户ID。 |
RESOURCE_ID |
视图所属资源 |
当前视图关联的 |
|
POSITION 和 NAME 构造的视图的核心维度,在系统出现不同需求时会起重要作用:
此处解释一下模块的概念,此处的 模块 并非我们开发过程中的模块,此处的模块底层关联模型只有一个,而模块更多是从列表作为入口。例如:
而且 POSITION 会比资源多一个维度,通常资源是后接口绑定,如
|
安全视图类
Zero中存在一个特殊的参数对象:
public class Vis extends JsonObject
// 该参数对象使用时可如下:
@POST
@Path("/{actor}/search")
@Address(Addr.Post.SEARCH)
@Adjust(Orders.MODULE)
JsonObject search(@PathParam("actor") String actor,
@BodyParam JsonObject data,
@QueryParam(KName.MODULE) String module,
@PointParam(KName.VIEW) Vis view);
该参数的格式比较特殊,通常使用的是 [view,position] 的数据格式,也是此处的 @PointParam 注解解析的内容,它可以将上述格式直接解析成视图的两个核心维度( NAME, POSITION ),并将该维度应用于任意支持它的接口。
窗口定义
安全视图的窗口定义主要依靠下边几个字段:
| 字段名 | 含义 |
|---|---|
PROJECTION |
JsonArray格式,执行该视图的列过滤,直接过滤掉接口返回数据的列信息。 |
CRITERIA |
JsonObject格式,执行该视图默认的 |
ROWS |
JsonObject格式,针对行数据执行筛选,生成 |
VISITANT |
布尔值,是否启用 虚拟视图(资源访问者)。 |
-
PROJECTION会作用于不同类型的前端组件,通常用于LIST/FORM两种,Zero框架中的保存列表的列信息以及表单中针对部分表单执行字段过滤就依赖它来完成,它是后置过滤(实际会从数据库中查询出所有信息进行值提取,现阶段没有明显的性能问题)。 -
CRITERIA主要针对于查询,它会隐式修改查询引擎的Qr语法,导致前端发送查询条件在安全视图作用下被直接修改,如果用户中出现了多个角色、多个用户组,则按照最终资源需求中定义的 Profile 来完成查询条件的拼合,默认模式下多个角色之间使用OR连接符。 -
ROWS针对特殊资源提取,提供基于主键的直接命中条件,解决异构查询模式下用户无法使用Join的情况,由于表单是单条数据记录,所以一般表单接口无法支持该属性(设置了也没有效果);通常此属性作用于列表:-
DATA:在数据层面,列表处理过程中直接针对条件执行过滤,典型应用为:菜单筛选、字典筛选、分类树筛选。
-
META:元数据层面,处理过程中只读取ROWS中设置过的的信息(特殊模式下载界面呈现模式出现ReadOnly时,它的定义位于UI配置中,而不是安全视图层。
-
|
虚拟视图(资源访问者)部分参考下一个章节的详细说明,上述限制中,虽然 |
视图检索流程
看完了上述安全视图的方方面面之后,视图检索流程就变得异常简单了,后端会根据访问资源键值生成 session-<METHOD>:<URI>:<POSITION>/<VIEW> 格式的视图缓存键,下边是用户访问某个资源接口时的详细流程:
-
用户发送请求到某个资源接口如:
/api/xxx/resource。 -
系统检索该资源是否存在用户级的
S_VIEW记录(OWNER_TYPE = USER, OWNER = <USER_ID>),如果存在该记录,则直接提取安全视图记录对资源执行前后(BEFORE/AFTER)计算。 -
若不存在用户级的
S_VIEW记录,则继续检索是否有角色级的S_VIEW记录,若存在则计算。 -
上述两步都不存在时,忽略安全视图,可访问所有内容。
|
从上述流程可以知道,用户级安全视图优先级比角色高,一般用户级安全视图都是个人视图模式存在,比如某个模块的视图管理,而角色级的视图都是管理员预设,单个用户不可以更改,比如管理员直接针对财务人员以外的角色设置不可访问某些资源的固定列如薪资、账期等。 |
最终 访问多少 的问题就直接被安全视图处理掉了,不同角色不同用户在此框架之下访问同一个接口时返回数据就可能出现不同,那么这样就解决了资源重用并且 访问多少 的问题。